using System;
using System.Threading;
using System.Net.Sockets;
using System.Windows.Forms;

//Copyright 2009 (c) SocketDemo.

namespace SocketDemo
{
    /// <summary>
    /// Listener Helper.
    /// </summary>
    public class ListenerHelper
    {
        #region field

        public delegate void ReceiveData(TcpClient client);

        public static ReceiveData delReceive = null;

        #endregion

        #region method

        #region CreateTcpListener

        public static TcpListener CreateTcpListener(int port)
        {
            return new TcpListener(System.Net.IPAddress.Any, port);
        }

        #endregion

        #region StartListen

        /// <summary>
        /// Start Listening
        /// </summary>
        public static void StartListening(ref TcpListener tcpListener, int port)
        {
            if (tcpListener != null)
            {
                tcpListener.Stop();
            }
            else
            {
                tcpListener = CreateTcpListener(port);
            }

            ListenerAndClient objListenerAndClient = new ListenerAndClient();

            objListenerAndClient.Listener = tcpListener;

            try
            {
                tcpListener.Start();
            }
            catch (SocketException ex)
            {
                ExceptionHelper.ShowException(ex);
                return;
            }

            tcpListener.BeginAcceptTcpClient(
                new AsyncCallback(DoAcceptTcpClientCallback), objListenerAndClient);

        }
        #endregion

        #region StopListen

        /// <summary>
        /// Stop Listen
        /// </summary>
        public static void StopListening(ref TcpListener tcpListener)
        {
            if (tcpListener != null)
            {
                tcpListener.Stop();
            }
        }

        #endregion



        public static void DoAcceptTcpClientCallback(IAsyncResult ar)
        {
            ListenerAndClient objListenerAndClient = (ListenerAndClient)ar.AsyncState;
            TcpClient client = null;

            try
            {
                client = objListenerAndClient.Listener.EndAcceptTcpClient(ar);
                objListenerAndClient.Client = client;
            }
            catch (ObjectDisposedException ex)
            {
                //Stop Listening 

                if (objListenerAndClient.Client != null)
                {
                    objListenerAndClient.Client.Close();
                }

                //ExceptionHelper.ShowException(ex);

                return;
            }

            new ReceiveData(HandleReceive).BeginInvoke(client,
                new AsyncCallback(ReceiveCallback), objListenerAndClient.Listener);

            objListenerAndClient.Listener.BeginAcceptTcpClient(
             new AsyncCallback(DoAcceptTcpClientCallback), objListenerAndClient);
        }

        public static void HandleReceive(TcpClient client)
        {
            LogHelper.ShowLog("Receive connect\t" + DateTime.Now.ToString() + "\t" +
             client.GetHashCode().ToString());

            Program.frmMainForm.delAddClient.Invoke(client);

            ClientConnection objClientConnection = new ClientConnection(client);
            objClientConnection.OnMessageReceived += new MessageReceive(OnReceive);
            objClientConnection.OnRemoteHostClosed += new RemoteHostClose(OnRemoteHostClose);
        }

        public static void ReceiveCallback(IAsyncResult ar)
        {
            //do nothing
            //TcpListener listener = (TcpListener)ar.AsyncState;
        }

        private static void OnReceive(ClientConnection sender, string data)
        {
            try
            {
                LogHelper.ShowLog("Receive\t\t" + DateTime.Now.ToString() + "\t" +
                    sender.Client.GetHashCode().ToString() + "\t" + data);
            }
            catch (Exception ex)
            {
                ExceptionHelper.ShowException(ex);
            }
        }

        private static void OnRemoteHostClose(ClientConnection sender)
        {
            LogHelper.ShowLog("Remote closed\t" + DateTime.Now.ToString() + "\t" +
                sender.Client.GetHashCode());

            Program.frmMainForm.delRemoveClient.Invoke(sender.Client);
        }

        #endregion

        #region struct

        struct ListenerAndClient
        {
            public TcpListener Listener;
            public TcpClient Client;
        }

        #endregion
    }
}
